
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.*;

import xmlParser.XmlParser;

import mover.SpringFactory;

import extensible.Canvas;

import java.awt.event.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

/**
 * Creates an applet that be viewed over the web.
 * 
 * @author Jonathan Su and Jeff Forte
 * 
 */
@SuppressWarnings("serial")
public class Applet extends JApplet {
	// constants
	public static final String MOVERS_LABEL = "Number of springs";
	public static final int MIN_MOVERS = 1;
	public static final int MAX_MOVERS = 20;
	public static final String TRAIL_LABEL = "Length of trail to display";
	public static final int MIN_TRAIL = 0;
	public static final int MAX_TRAIL = 30;
	public static final String DISTANCE_LABEL = "Distance between birds";
	public static final int MIN_DISTANCE = 1;
	public static final int MAX_DISTANCE = 256;
	public static final String PROXIMITY_LABEL = "Prox. between birds";
	public static final int MIN_PROXIMITY = 1;
	public static final int MAX_PROXIMITY = 256;
	public static boolean READ_FROM_FILE = false;
	public static XmlParser PARSER; 
	// animate 25 times per second if possible
	public static final int DEFAULT_DELAY = 1000 / 25; // in milliseconds
	protected static JFileChooser ourOpenChooser = new JFileChooser(System
			.getProperties().getProperty("user.dir"));
	protected static JFileChooser ourSaveChooser = new JFileChooser(System
			.getProperties().getProperty("user.dir"));
	
	
	// state
	private Canvas myDisplay;
	private Timer myTimer;

	/**
	 * Initializes the applet --- called by the browser.
	 */
	public void init() {
		// create container to display animations
		init(new Dimension(Integer.parseInt(getParameter("width")), Integer
				.parseInt(getParameter("height"))));
	}

	/**
	 * Initializes the applet --- called by main.
	 */
	public void init(Dimension size) {
		// create container to display animations
		myDisplay = new Canvas(size);
		myDisplay.setPreferredSize(size);
		myDisplay.setSize(size);
		myDisplay.setFocusable(true);
		myDisplay.requestFocus();

		SpringAndMassParametersPanel sliders = new SpringAndMassParametersPanel();

		RangeSlider movers = new RangeSlider(MOVERS_LABEL, MIN_MOVERS,
				MAX_MOVERS, 1, 2);
		RangeSlider trail = new RangeSlider(TRAIL_LABEL, MIN_TRAIL, MAX_TRAIL, 0, 2);
		RangeSlider distance = new RangeSlider(DISTANCE_LABEL, MIN_DISTANCE,
				MAX_DISTANCE,1,1);
		RangeSlider proximity = new RangeSlider(PROXIMITY_LABEL, MIN_PROXIMITY,
				MAX_PROXIMITY,1,1);
		sliders.setLayout(new GridLayout(10, 1));
		sliders.add(movers);
		sliders.add(trail);
		sliders.addParameterSlider("lengthScale", "scale length of spring", 1, 4, 1, 1);
		sliders.addParameterSlider("kValScale", "scale k value of spring", 1, 4, 1, 1);
		sliders.addParameterSlider("massScale", "scale mass of ball", 1, 4, 1, 1);
		sliders.addParameterSlider("gravityAngle", "direction of gravity", 0, 360, 90, 15);
		
		JMenuBar bar = new JMenuBar();
		bar.add(makeFileMenu());
		setJMenuBar(bar);
		
		// Create bottom panel buttons.
		ButtonPanel options = new ButtonPanel(myDisplay, movers, trail,
				distance, proximity);
		makeButtons(options);

		// Create checkboxes for border options.
		// need to figure out how to make them exclusive.
		JPanel borderBoxes = makeCheckBoxes();

		// add our user interface components to applet
		// getContentPane().add(commands, BorderLayout.NORTH);
		getContentPane().add(myDisplay, BorderLayout.CENTER);
		getContentPane().add(sliders, BorderLayout.EAST);
		getContentPane().add(options, BorderLayout.SOUTH);
		getContentPane().add(borderBoxes, BorderLayout.WEST);
	}

	/**
	 * 
	 * @return JPanel
	 * 
	 * JPanel returned holds wrap checkbox for boarder recognition.
	 */
	private JPanel makeCheckBoxes() {
		JPanel borderBoxes = new JPanel();
		borderBoxes.setLayout(new GridLayout(20, 1));
		JCheckBox wrap = new JCheckBox("Wrap", true);
		wrap.addActionListener(new WrapListener(myDisplay));
		borderBoxes.add(wrap);
		return borderBoxes;
	}

	/**
	 * 
	 * @param options
	 * 
	 * create all buttons for options panel and add them to options panel.
	 */
	private void makeButtons(ButtonPanel options) {
		// allows for vertical slider layout.
		options.setLayout(new GridLayout(1, 10));
		
		JButton stepButton = new JButton("Step");
        stepButton.addActionListener(new StepListener(myDisplay));
        options.add(stepButton);
    
        JButton startButton = new JButton("Start");
        startButton.addActionListener(new StartListener(this));
        options.add(startButton);
        
        JButton stopButton = new JButton("Pause");
        stopButton.addActionListener(new PauseListener(this));
        options.add(stopButton);

		JButton clear = new JButton("Clear");
		clear.addActionListener(new ClearListener(myDisplay));
		options.add(clear);
		
		options.add(new SpringFactory());
		
		JButton removeIndividual = new JButton("Remove Component of Spring");
		removeIndividual.addActionListener(new RemoveIndividualListener(
				myDisplay));
		options.add(removeIndividual);
	}
	
	/**
     * makes the File Menu which is at the top of the applet
     * allows the user to save, open a file, and quit.
     * @return the file Menu which is a JMenu
     */
    private JMenu makeFileMenu() {
		JMenu fileMenu = new JMenu("File");

		fileMenu.add(new AbstractAction("Open File") {
			public void actionPerformed(ActionEvent ev) {
				int retval = ourOpenChooser.showOpenDialog(null);
				if (retval == JFileChooser.APPROVE_OPTION) {
					File file = ourOpenChooser.getSelectedFile();
					System.out.println("you chose to open this file: " + file );
					PARSER = new XmlParser();
					PARSER.parseXmlFile(file);
					PARSER.parseDocument();
					READ_FROM_FILE = true;
				}
			}
		});
		fileMenu.add(new AbstractAction("Save"){
			public void actionPerformed(ActionEvent e) {
				int retval = ourSaveChooser.showSaveDialog(null);
				if (retval == JFileChooser.APPROVE_OPTION) {
					File file = ourSaveChooser.getSelectedFile();
					try {
						PrintWriter pw = new PrintWriter(file, "UTF8");
						pw.close();
						System.out.println("saved");
					} catch (FileNotFoundException e1) {
						System.out.println("could not open "+file);
					} catch (UnsupportedEncodingException e2) {
						System.out.println("problem with UTF8 encoding");
					} 
				}
			}
			
		});
		fileMenu.add(new AbstractAction("Quit") {
			public void actionPerformed(ActionEvent ev) {
				System.exit(0);
			}
		});
		return fileMenu;
	}

	/**
	 * Starts the applet's action, i.e., starts the animation.
	 */	
	public void start ()
    {
        // create a timer to animate the canvas
        myTimer = new Timer(DEFAULT_DELAY, 
            new ActionListener()
            {
                long lastTime = 0;
                long elapsedTime = 0;
                int numFrames = 0;

                public void actionPerformed(ActionEvent e)
                {
                    myDisplay.update();
                    myDisplay.repaint();
                    myTimer.setDelay(Math.max(1, DEFAULT_DELAY - calculateFrameRate()));
                }

                private int calculateFrameRate ()
                {
                    numFrames++;
                    long currentTime = System.currentTimeMillis();
                    elapsedTime += (currentTime - lastTime);
                    if (elapsedTime >= 1000)
                    {
                        elapsedTime = 0;
                        numFrames = 0;
                    }
                    int stepTime = (int)(currentTime - lastTime);
                    lastTime = currentTime;
                    return stepTime;
                }
            });
        // start the animation
        myTimer.start();
    }

	/**
	 * Stops the applet's action, i.e., the animation.
	 */
	public void stop() {
		// stop the animation
		myTimer.stop();
	}
}
